//
// Created by wxd on 2025/7/15.
// 资源加载工具类
//

#pragma once

#include "stb/stb_image.h"
#include <memory>
#include <mutex>
#include <unordered_map>
#include <string>

struct ImageParam {
    int width;
    int height;
    int channels;
    stbi_uc* data;

    ImageParam() : width(0), height(0), channels(0), data(nullptr) {}

    ImageParam(int w, int h, int channel, stbi_uc* data) : width(w), height(h), channels(channel), data(data) {}

    ~ImageParam() = default;

    void release() const {
        if (data != nullptr) {
            stbi_image_free(data);
        }
    }
};

class ResourceLoadUtils {
public:
    ResourceLoadUtils(const ResourceLoadUtils&) = delete;
    ResourceLoadUtils& operator=(const ResourceLoadUtils&) = delete;

    ~ResourceLoadUtils();

    static ResourceLoadUtils& getInstance();
    static void clearImageCache();

    /**
     * Note: 如果函数中创建了ImageParam, 相当于是局部变量，在结束的时候，会自动调用 ImageParam 析构函数，释放内部的data指针，这个指向的是纹理数据
     *       会出现在向显存传递data的时候，该地址找不到，从而报错
     * 解决方式：去掉析构函数，手动提供release来释放纹理数据，既避免了内存泄漏，又不会出现上述问题，不建议将局部变量使用static修饰的方式来延长生命周期，这样
     * 会导致整体内存上涨
     */
    ImageParam loadImage(const char* imagePath);
    ImageParam loadImage(const char* imagePath, const bool flip);
    ImageParam loadImage(const char* imagePath, const bool flip, int req_comp);
    ImageParam loadImage(const std::string& imagePath);
    ImageParam loadImage(const std::string& imagePath, const bool flip);
    ImageParam loadImage(const std::string& imagePath, const bool flip, int req_comp);


private:
    ResourceLoadUtils() {}

    static void init();

    // note: 如果是用独占指针，这里直接通过std::make_unique的方式创建的时候会调用当前对象的构造，但是单例模式下，我们需要将构造私有化
    //       导致独占指针调用的时候找不到构造，从而报错。解决方式：使用reset方式手动通过new的方式在类内创建对象给到独占指针
    static std::unique_ptr<ResourceLoadUtils> instance;

    static std::once_flag m_InitFlag; // 用于线程安全的初始化

    static std::unordered_map<const char*, ImageParam> m_LoadImageMap; // 用于缓存已经加载的纹理
};



